1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
use super::*;
use indexmap::Equivalent;

/// The hash-code of a value
#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Code(pub u64);

impl Code {
    /// Create a new code given a pre and post annotation hash, as well as whether this term is in HNF, BNF, or NF
    #[inline]
    pub const fn new(pre: u64, post: u64) -> Code {
        Code((pre & 0x00000000FFFFFFFF) | (post & 0xFFFFFFFF00000000))
    }
    /// Get the pure, untyped component of this code
    #[inline]
    pub const fn pure(self) -> u32 {
        self.0 as u32
    }
}

impl Debug for Code {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{:#x}", self.0)
    }
}

impl Equivalent<TermId> for Code {
    #[inline]
    fn equivalent(&self, key: &TermId) -> bool {
        *self == key.code()
    }
}

/// Forms a term can be in
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Form {
    /// No particular form
    Null = 0b000,
    /// Head normal form
    Head = 0b001,
    /// Beta normal form
    Beta = 0b011,
    /// Eta normal form
    Eta = 0b100,
    /// Head eta normal form
    HeadEta = 0b101,
    /// Beta-eta normal form
    BetaEta = 0b111,
}

impl Form {
    /// Convert a `u8` into a form
    #[inline]
    pub const fn from_u8(x: u8) -> Form {
        use Form::*;
        match x {
            0b000 => Null,
            0b001 => Head,
            0b011 => Beta,
            0b100 => Eta,
            0b101 => HeadEta,
            0b111 => BetaEta,
            _ => Null,
        }
    }

    /// Get whether this form is head normal
    #[inline]
    pub const fn is_hnf(self) -> bool {
        self as u8 & Form::Head as u8 != 0
    }

    /// Get whether this form is beta normal
    #[inline]
    pub const fn is_bnf(self) -> bool {
        self as u8 & Form::Beta as u8 != 0
    }

    /// Get whether this form is eta normal
    #[inline]
    pub const fn is_enf(self) -> bool {
        self as u8 & Form::Eta as u8 != 0
    }

    /// Get the larger form
    #[inline]
    pub const fn join(self, other: Form) -> Form {
        Self::from_u8(self as u8 | other as u8)
    }

    /// Get the smaller form
    #[inline]
    pub const fn meet(self, other: Form) -> Form {
        Self::from_u8(self as u8 & other as u8)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn code_construction_sanity() {
        assert_ne!(Code::new(0x10, 0x0), Code::new(0x20, 0x0));
    }
}